package fem2.mesh_and_topology;

import math2.MathUtilities;

/**
 * Spatial criteria to check if coeffs[0] point lie in coeffs[0] surface
 * 
 * @author hbui
 * 
 */
public class SurfaceSpatialCriteria extends SpatialCriteria {

	private double[] coeffs;

	/**
	 * surface ax + by + c = 0
	 * 
	 * @param a
	 * @param b
	 * @param c
	 */
	public SurfaceSpatialCriteria(double a, double b, double c) {
		coeffs = new double[] { a, b, c };
	}

	/**
	 * surface ax + by + cz + d = 0
	 * 
	 * @param a
	 * @param b
	 * @param c
	 * @param d
	 */
	public SurfaceSpatialCriteria(double a, double b, double c, double d) {
		coeffs = new double[] { a, b, c, d };
	}

	@Override
	public boolean isSatisfied(double... x) {
		if (coeffs.length == 3) {
			return Math.abs(coeffs[0] * x[0] + coeffs[1] * x[1] + coeffs[2]) < MathUtilities.tol14;
		} else if (coeffs.length == 4) {
			return Math.abs(coeffs[0] * x[0] + coeffs[1] * x[1] + coeffs[2] * x[2] + coeffs[3]) < MathUtilities.tol14;
		} else {
			throw new Error("invalid dimension");
		}
	}

	@Override
	public boolean isIntersected(double x0, double y0, double size) {
		double d1 = coeffs[0] * x0 + coeffs[1] * y0 + coeffs[2];
		double d2 = coeffs[0] * (x0 + size) + coeffs[1] * y0 + coeffs[2];
		double d3 = coeffs[0] * (x0 + size) + coeffs[1] * (y0 + size) + coeffs[2];
		double d4 = coeffs[0] * x0 + coeffs[1] * (y0 + size) + coeffs[2];

		double dmin = Math.min(Math.min(d1, d2), Math.min(d3, d4));
		double dmax = Math.min(Math.max(d1, d2), Math.max(d3, d4));

		return dmin * dmax <= 0;
	}

	@Override
	public boolean isIntersected(double x0, double y0, double z0, double size) {
		double d1 = coeffs[0] * x0 + coeffs[1] * y0 + coeffs[2] * z0 + coeffs[3];
		double d2 = coeffs[0] * (x0 + size) + coeffs[1] * y0 + coeffs[2] * z0 + coeffs[3];
		double d3 = coeffs[0] * (x0 + size) + coeffs[1] * (y0 + size) + coeffs[2] * z0 + coeffs[3];
		double d4 = coeffs[0] * x0 + coeffs[1] * (y0 + size) + coeffs[2] * z0 + coeffs[3];
		double d5 = coeffs[0] * x0 + coeffs[1] * y0 + coeffs[2] * (z0 + size) + coeffs[3];
		double d6 = coeffs[0] * (x0 + size) + coeffs[1] * y0 + coeffs[2] * (z0 + size) + coeffs[3];
		double d7 = coeffs[0] * (x0 + size) + coeffs[1] * (y0 + size) + coeffs[2] * (z0 + size)
				+ coeffs[3];
		double d8 = coeffs[0] * x0 + coeffs[1] * (y0 + size) + coeffs[2] * (z0 + size) + coeffs[3];

		double dmin = Math.min(Math.min(Math.min(d1, d2), Math.min(d3, d4)),
				Math.min(Math.min(d5, d6), Math.min(d7, d8)));
		double dmax = Math.max(Math.max(Math.max(d1, d2), Math.max(d3, d4)),
				Math.max(Math.max(d5, d6), Math.max(d7, d8)));

		return dmin * dmax <= 0;
	}

}
